﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Threading;
using System.Threading;

namespace Dimok.Schedulers {
	public class Scheduler {
		public class TimerErrorException : EventArgs {
			public Exception Exception;
			public TimerErrorException(Exception exception) {
				Exception = exception;
			}
		}
		public delegate void CommandDelegate();
		public event EventHandler<TimerErrorException> Error;
		System.Windows.Threading.DispatcherTimer _time;
		CommandDelegate _command;
		private bool _isRunning;
		public bool IsRunning {
			get { return _isRunning; }
			private set { _isRunning = value; }
		}
		public TimeSpan Delay {
			get { return _time.Interval; }
			set { _time.Interval = value; }
		}

		public CommandDelegate Command {
			get { return _command; }
			set {
				_time.Stop();
				_command = value;
				_time.Start();
			}
		}
		public Scheduler(TimeSpan delay) {
			_time = new DispatcherTimer() { Interval = delay };
			_time.Tick+= _time_Tick;
		}
		public static void Run(TimeSpan delay, CommandDelegate command) {
			new Dimok.Schedulers.Scheduler(delay).Command = command;
		}

		public void Cancel() {
			IsRunning = false;
			_time.Stop();
		}

		void _time_Tick(object sender, EventArgs e) {
			try {
				var t = (DispatcherTimer)sender;
				if (!t.IsEnabled) return;
				t.Stop();
				IsRunning = true;
				Command();
			} catch (Exception exc) {
				if (Error != null) Error(this, new TimerErrorException(exc));
			} finally {
				IsRunning = false;
			}
		}
	}

	public class ThreadScheduler {
		public class TimerErrorException : EventArgs {
			public Exception Exception;
			public TimerErrorException(Exception exception) {
				Exception = exception;
			}
		}
		public event EventHandler<TimerErrorException> Error;
		TimeSpan _period = new TimeSpan(0, 0, 0, 0, -1);
		System.Threading.Timer _timer;
		TimeSpan _delay = new TimeSpan(0, 0, 0, 0, 500);
		private bool _isRunning;
		public bool IsRunning {
			get { return _isRunning; }
			private set { _isRunning = value; }
		}
		public TimeSpan Delay {
			get { return _delay; }
			set {
				_delay = value;
				if (_timer != null)
					_timer.Change(value, _period);
			}
		}
		public Action Command { set { Init(value); } }
		public void Init(Action command) { Init(command, TimeSpan.MinValue); }
		public void Init(Action command, TimeSpan delay) {
			Cancel();
			if (delay != TimeSpan.MinValue) Delay = delay;
			_timer = new Timer(o => {
				IsRunning = true;
				try {
					command();
					Cancel();
				} catch (Exception exc) {
					if (Error != null) Error(this, new TimerErrorException(exc));
				} finally {
					IsRunning = false;
				}
			},
			null, Delay, _period);
		}
		public ThreadScheduler() { }
		public ThreadScheduler(TimeSpan delay) {
			Delay = delay;
		}

		public void Cancel() {
			if (_timer != null) {
				_timer.Change(System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);
				_timer.Dispose();
				_timer = null;
			}
		}

	}


}
